//
//  TableViewModel.swift
//  TSKit
//
//  Created by chenyusen on 2018/3/16.
//

import UIKit


public class TableViewModel: NSObject {
    var sections: [TableSectionItem] = []
    var sectionIndexTitles: [String]?
}

// MARK: - 增删改查
public extension TableViewModel {
    
    
    /// 向tableViewModel添加一个cellItem,默认往最有一个section添加
    ///
    /// - Parameter cellItem: cellItem实例
    /// - Returns: 返回最后一个section的rows
    @discardableResult
    func add(_ cellItem: TableCellItem) -> [TableCellItem] {
        return add([cellItem])
    }
    
    
    /// 向tableViewModel添加一组cellItem,默认往最有一个section添加
    ///
    /// - Parameter cellItems: cellItem数组
    /// - Returns: 返回最后一个section的rows
    @discardableResult
    func add(_ cellItems: [TableCellItem]) -> [TableCellItem] {
        if sections.count == 0 {
            sections.append(TableSectionItem())
        }
        sections.last!.rows.append(contentsOf: cellItems)
        return sections.last!.rows
    }
    
    
    /// 向tableViewModel添加一个section
    ///
    /// - Parameter section: SectionItem实例
    /// - Returns: 添加完后的sections
    func add(_ section: TableSectionItem) -> [TableSectionItem] {
        return add([section])
    }
    
    
    /// 向tableViewModel添加多组section
    ///
    /// - Parameter sections: SectionItem数组
    /// - Returns: 添加完后的sections
    @discardableResult
    func add(_ sections: [TableSectionItem]) -> [TableSectionItem] {
        self.sections.append(contentsOf: sections)
        return self.sections
    }
    
    
    /// 删除一个cellItem
    ///
    /// - Parameters:
    ///   - cellItem: 待删除的cellItem
    ///   - indexPath: cellItem所在位置
    /// - Returns: 返回sections
    @discardableResult
    func remove(cellItemAt indexPath: IndexPath) ->  [TableSectionItem] {
        assert(indexPath.section < sections.count)
        let section = sections[indexPath.section]
        assert(indexPath.row < section.rows.count)
        section.rows.remove(at: indexPath.row)
        return sections
    }
    
    
    /// 删除一组cellItems
    ///
    /// - Parameter sectionIndex: 待删除组的index
    /// - Returns: 返回sections
    @discardableResult
    func remove(sectionAt sectionIndex: Int) ->  [TableSectionItem] {
        assert(sectionIndex < sections.count)
        if sectionIndex < sections.count {
            sections.remove(at: sectionIndex)
        }
        return sections
    }
    
    
    /// 清空所有section
    func removeAll() {
        sections = []
    }
    
    
    /// 将一个cellItem插入都section某个位置
    ///
    /// - Parameters:
    ///   - cellItem: cellItem对象
    ///   - row: 指定行数
    ///   - section: 指定组index
    /// - Returns: 插入成功后的indexPath
    @discardableResult
    func insert(_ cellItem: TableCellItem,
                at row: Int,
                section: Int = 0) -> IndexPath? {
        let success = insert([cellItem], at: row, section: section)
        return success ? IndexPath(row: row, section: section) : nil
    }
    
    
    /// 将一组cellItem插入都section某个位置
    ///
    /// - Parameters:
    ///   - cellItems: cellItem对象数组
    ///   - row: 指定行数
    ///   - section: 指定组index
    /// - Returns: 插入是否成功
    @discardableResult
    func insert(_ cellItems: [TableCellItem],
                at row: Int,
                section: Int = 0) -> Bool {
        assert(sections.count > section)
        if sections.count > section {
            sections[section].rows.insert(contentsOf: cellItems, at: 0)
            return true
        } else {
            return false
        }
    }
    
    
    /// 删除指定cellItem
    ///
    /// - Parameter cellItem: 指定的cellItem
    @discardableResult
    func remove(_ cellItem: TableCellItem) -> IndexPath? {
        for (sectionIndex, section) in sections.enumerated() {
            if let rowIndex = section.rows.index(of: cellItem) {
                section.rows.remove(at: rowIndex)
                return IndexPath(row: rowIndex, section: sectionIndex)
            }
        }
        return nil
    }
    
    
    /// 获取指定indexPath的cellItem
    ///
    /// - Parameter indexPath:
    /// - Returns: indexPath位置的cellItem
    func cellItem(at indexPath: IndexPath) -> TableCellItem? {
        let section = indexPath.section
        let row = indexPath.row
        
        assert(section < sections.count)
        if section < sections.count {
            let rows = sections[section].rows
            if row < rows.count {
                return rows[row]
            }
        }
        return nil
    }
    
    
    /// 获取某个section的cellItems
    ///
    /// - Parameter section: 指定sectionIndex
    /// - Returns: cellItem数组
    func cellItems(at section: Int = 0) -> [TableCellItem] {
//        assert(section < sections.count)
        if section < sections.count {
            return sections[section].rows
        } else {
            return []
        }
    }
    
    
    /// 获取所有的cellItems
    ///
    /// - Returns: cellItem数组
    func allCellItems() -> [TableCellItem] {
        var cellItems: [TableCellItem] = []
        sections.forEach { (secionItem) in
            cellItems.append(contentsOf:secionItem.rows)
        }
        return cellItems
    }
    
    /// 获取某个sectionItem
    ///
    /// - Parameter section: 指定sectionIndex
    /// - Returns: 指定sectionItem
    func sectionItem(at section: Int = 0) -> TableSectionItem? {
        assert(section < sections.count)
        if section < sections.count {
            return sections[section]
        } else {
            return nil
        }
    }
}

extension TableViewModel {
    private func cell(with cellClass: UITableViewCell.Type,
                      tableView: UITableView,
                      cellItem: TableCellItem) -> UITableViewCell {
        if let cellClass = cellClass as? TableCell.Type {
            var identifier = "\(cellClass)"
            if cellClass.shouldAppendCellItemClassToReuseIdentifier {
                identifier.append("\(cellItem)")
            }
            
            var cell = tableView.dequeueReusableCell(withIdentifier: identifier)
            if cell == nil {
                cell = cellClass.init(style: .default, reuseIdentifier: identifier)
            }
            (cell as? TableCell)?.updateCell(cellItem)
            
            return cell!
        }
        fatalError("why cell is nil")
    }
    
    private func cell(with cellNib: UINib,
                      tableView: UITableView,
                      indexPath: IndexPath,
                      cellItem: TableCellItem) -> UITableViewCell {
        let identifier = "\(cellNib.self)"
        tableView.register(cellNib, forCellReuseIdentifier: identifier)
        let cell = tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath)
        (cell as? TableCell)?.updateCell(cellItem)
        return cell
    }
}


extension TableViewModel: UITableViewDataSource {
    
    public func numberOfSections(in tableView: UITableView) -> Int {
        return sections.count
    }
    
    public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        assert(section < sections.count || 0 == sections.count)
        if section < sections.count {
            return sections[section].rows.count
        }
        return 0
    }
    
    public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if let aCellItem = cellItem(at: indexPath) {
            if let cellClass = aCellItem.cellClass {
                return cell(with: cellClass, tableView: tableView, cellItem: aCellItem)
            } else if let cellNib = aCellItem.cellNib {
                return cell(with: cellNib, tableView: tableView, indexPath: indexPath, cellItem: aCellItem)
            }
            fatalError()
        } else {
            fatalError()
        }
    }
    
    public func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {
        if let sectionItem = sectionItem(at: section) {
            return sectionItem.footerTitle
        } else {
            return nil
        }
    }
    
    public func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        if let sectionItem = sectionItem(at: section) {
            return sectionItem.headerTitle
        } else {
            return nil
        }
    }
    
    public func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
        if let rowActions = cellItem(at: indexPath)?.rowActions {
            return rowActions.count > 0
        }
        return false
    }
}
